// encoding utf-8
#ifndef __Qsi__
#define __Qsi__

#include <QtCore/QMap>
#include <QtCore/QObject>
#include <QtScript/QtScript>

/*! @defgroup Qsi Интерпретатор скриптов
*/

//! Пространство имен интерпретатора скриптов
namespace Qsi {


/*! \brief Отладчик
	\ingroup Qsi
*/
class Debugger : public QObject, public QScriptEngineAgent {
	Q_OBJECT
public:
	explicit Debugger( QScriptEngine * engine );
	virtual ~Debugger() {}

	int lineDelay() const { return p_lineDelay; } //!< Задержка при переходе от строки до строки
	bool isLineDelayEnabled() const { return p_lineDelayEnabled; } //!< Включина ли задержка при переходе между строками

public slots:
	void setLineDelay( int delay ) { p_lineDelay = delay; } //!< Установить кол-во миллисекунд, которое интерпретатор будет ждать при переходе от строки к строке
	void setLineDelayEnabled( bool enabled ) { p_lineDelayEnabled = enabled; } //!< Вкл/выкл задержку при переходе между строками

signals:
	void positionChanged( int lineNumber, int columnNumber ); //!< Текущаяя строка изменилась
	void error( const QString & str ); //!< Ошибка
	void exeptionThrowed( const QScriptValue & exeption ); //!< Брошено исключение
	void exeptionCatched( const QScriptValue & exeption, bool hasHandler ); //!< Поймано исключение
	void functionCalled(); //!< Функция вызвана
	void functionFinished( const QScriptValue & returnValue ); //!< Функция выполнена
	void scriptLoaded( const QString & fileName, int baseLineNumber ); //!< Скрипт загружен
	void scriptUnloaded(); //!< Скрипт завершен

protected:
	virtual void positionChange( qint64 scriptId, int lineNumber, int columnNumber );
	virtual void exceptionCatch( qint64 scriptId, const QScriptValue & exception );
	virtual void exceptionThrow( qint64 scriptId, const QScriptValue & exception, bool hasHandler );
	virtual void functionEntry( qint64 scriptId );
	virtual void functionExit( qint64 scriptId, const QScriptValue & returnValue );
	virtual void scriptLoad( qint64 id, const QString & program, const QString & fileName, int baseLineNumber );
	virtual void scriptUnload( qint64 id );

private:
	int p_lineDelay;
	bool p_lineDelayEnabled;

};


/*! \brief Интерпретатор
	\ingroup Qsi
*/
class Interpreter : public QObject {
	Q_OBJECT
public:
	explicit Interpreter( QObject * parent = 0 );
	virtual ~Interpreter();

	bool evaluateFile( const QString & fileName ); //!< Выполнить файл
	Qsi::Debugger * debugger() const { return &p_debugger; } //!< Получить дебагер
	bool registerObject( QObject * object, const QString & name ); //!< Зарегестрировать глобальный объект
	template < typename MetaType >
	inline bool registerClass( const QString & name ) { //!< Зарегестрировать класс объектов. В качестве MetaType передается тип имеющий метаданные (например QObject)

		QScriptValue classPrototype = engine.scriptValueFromQMetaObject<QLineEdit>();
		bool ok = classPrototype.isValid();

		if (ok)
			engine.globalObject().setProperty( "QLineEdit", classPrototype );

		return ok;
	}

protected:
	QScriptEngine engine;
	Debugger p_debugger;

};

};

#endif//__Qsi__
